<?php
namespace App\Core;


use App\Exception\RouterException;

class Router
{
    const CONFIG_F_ROUTE = 'route';
    const CONFIG_N_MAPPINGS = 'mappings';
    const CONFIG_N_REGEX_FUNCTION = 'regex_function';

    const DEFAULT_REGEX_FUNCTION = 'preg_match';//'ereg';

    const CONFIG_N_REGEX_LABEL = 'regex_label';

    const DEFAULT_REGEX_LABEL = '#';//'';

    const HTTP404_CONTROLLER = '404';

    private $mappings;
    /**
     * @var App
     */
    private $_app;

    public function __construct(App $app)
    {
        $this->_app = $app;
    }

    public function get_mappings($key = '')
    {
        if (!empty($key))
            return $this->mappings[$key];
        else
            return $this->mappings;
    }

    /**
     * 从代码中设置或修改mapping表
     */
    public function set_mappings($mappings = array())
    {
        $this->mappings = $mappings;
    }

    /**
     * 根据URI 获取到对应的Controller
     *
     * @return string
     * @throws RouterException
     */
    public function route()
    {
        $app = $this->_app;

        if (empty($this->mappings)) {
            $mappings = $app->getConfig(self::CONFIG_N_MAPPINGS, self::CONFIG_F_ROUTE);
        } else {
            $mappings = $this->mappings;
        }

        $regex_function = $app->getConfig(self::CONFIG_N_REGEX_FUNCTION, self::CONFIG_F_ROUTE);
        if (!function_exists($regex_function)) {
            $regex_function = self::DEFAULT_REGEX_FUNCTION;
        }
        $regex_label = $app->getConfig(self::CONFIG_N_REGEX_LABEL, self::CONFIG_F_ROUTE);
        if (!$regex_label) {
            $regex_label = self::DEFAULT_REGEX_LABEL;
        }
        $uri = $this->_app->getRequest()->getRequestURI();
        if (defined('BASE_URI') && strpos($_SERVER['REQUEST_URI'], BASE_URI) === 0) {
            $uri = substr($uri, strlen(BASE_URI));
        }

        $pos = strpos($uri, '?');
        if ($pos) {
            $uri = substr($uri, 0, $pos);
        }
        if (empty($uri)) {
            $uri = '/';
        }

        $matches = array();
        foreach ($mappings as $controllerClassName => $patterns) {
            foreach ($patterns as $pattern) {
                if (@$regex_function($regex_label . $pattern . $regex_label, $uri, $matches)) {
                    $app->getRequest()->setRouterMatches($matches);
                    return $controllerClassName;
                }
            }
        }

        $controllerClassName = $app->getConfig(self::HTTP404_CONTROLLER, self::CONFIG_F_ROUTE);
        if ($controllerClassName) {
            return $controllerClassName;
        }

        throw new RouterException('Router Error');
    }
}